import { getToken, setToken, removeToken, setTimeStamp } from '@/utils/auth'
import { login, getUserInfo, getUserDetailById } from '@/api/user'
import { resetRouter } from '@/router'

// 状态
const state = {
  token: getToken(), // 设置token为共享状态 初始化vuex的时候，就先从缓存中读取
  userInfo: {} // 这里定义一个空对象 - 为什么呢？为什么不定义null呢？ - 因为我们会在 getters 中引用userinfo的变量，如果设置为null，则会引起异常和报错
}
// 修改状态
const mutations = {
  setToken(state, token) { // 这里的setToken不是上述引用的setToken - 因为参数不一致
    state.token = token // 一旦发生变化，就将数据设置给vuex - 没有设置给缓存
    // 同步给缓存
    setToken(token)
  },
  removeToken(state) {
    state.token = null // 将vuex的数据置空
    removeToken() // 缓存也置空
  },
  setUserInfo(state, result) {
    // 更新一个对象
    state.userInfo = result // 这样是响应式
    // state.userInfo = { ...result } // 写法二 - 这样也是响应式，属于浅拷贝
    // state.userInfo['username'] = result // 这样才不是响应式
  },
  // 删除用户信息 - 当切换用户和退出登录就删除
  reomveUserInfo(state) {
    state.userInfo = {}
  }
}
// 异步操作
const actions = { // actions其实就是给组件来调用的
  // 在登录请求成功后，返回的数据中有data - token，会将token数据给state，但是在给state之前，会先经过mutations
  async login(context, data) { // data为登录的手机号和密码
    // 调用api接口
    const result = await login(data) // 拿到token - result为返回的数据
    // axios默认给数据加了一层data
    // if (result.data.success) { // 为true - 登录成功 - 取data - token
    //   // 将数据同步给mutations，mutations再同步给缓存 - 这样重新登录时，token就有值了，在state里
    //   context.commit('setToken', result.data.data)
    // }

    // 有了响应拦截器中的处理，就不用再加if - 因为如果能执行到这个位置就说明成功了 - 因为失败了不会执行到这，在响应拦截器中就return到catch中了
    context.commit('setToken', result) // 设置token - 这里也不用加.data.data了

    // 设置当前时间戳
    setTimeStamp()
  }, // 现在别人想要用token得通过子模块访问，可以创建快捷访问方式让别人快速访问 - 在getters里设置
  async getUserInfo(context) {
    const result = await getUserInfo() // 获取结果就用await - 得到的数据是返回数据中的data，而不是success、code等
    // await - 强制执行
    // 获取用户详情 - 头像
    const baseInfo = await getUserDetailById(result.userId)
    const baseResult = { ...result, ...baseInfo } // 合并数据
    console.log(baseResult.staffPhoto)
    context.commit('setUserInfo', baseResult) // 提交到mutation - 修改数据
    return result // 这里是给我们后期做权限的时候留下的伏笔 - result就是当前用户的资料 用来获取里面的menus
  },
  // 登出操作
  logout(context) {
    // 删除token
    context.commit('removeToken')
    // 删除用户资料
    context.commit('reomveUserInfo')
    // 重置路由
    resetRouter()
    // 还有一步  vuex中的数据是不是还在
    // 要清空permission模块下的state数据 - 设置权限模块下路由为初始状态
    // vuex子模块怎么调用子模块的action？ - 都没加锁的情况下可以随意调用 - 因为不加命名空间的情况下 所有的mutations和action都是挂在全局上的 所以可以直接调用
    // 但是加了命名空间的子模块 怎么调用另一个加了命名空间的子模块的mutation？ - { root: true } 且第一个参数要加路径
    // 加了命名空间的context指的不是全局的context
    // mutation名称 载荷 payload 第三个参数  { root: true }
    // { root: true } 表示调用根级的子模块
    // vuex中 user子模块  permission子模块
    // 子模块调用子模块的action  默认情况下 子模块的context是子模块的
    // 父模块 调用 子模块的action
    context.commit('permission/setRoutes', [], { root: true })
    // 子模块调用子模块的action 可以 将 commit的第三个参数 设置成  { root: true } 就表示当前的context不是子模块了 而是父模块
  }
}

export default {
  namespaced: true, // 命名空间打开 - 模块和模块之间是封闭的
  state,
  mutations,
  actions
}

// 发起一个请求的步骤：配代理 -> 封装接口-api/user -> 写请求-store里的action -> 去组件中发起请求/调用action中的方法    中间还有其它流程，如将token放入state和本地
